package ink.xiaobaibai.rbac;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import ink.xiaobaibai.entity.AdminRole;
import ink.xiaobaibai.rbac.voter.RoleVoter;
import ink.xiaobaibai.service.impl.AdminRoleServiceImpl;
import javafx.util.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @description: rbac管理者
 * @author: 小白白
 * @create: 2021-05-15
 * 实现AccessDecisionManager接口,自己构建一个管理者
 **/

@Component
public class AccessDecisionManagerImpl implements AccessDecisionManager, ApplicationRunner {

    @Autowired
    private AdminRoleServiceImpl adminRoleService;

    private RoleVoter roleVoter;

    @Override
    public void run(ApplicationArguments args) {
        QueryWrapper<AdminRole> q1 = new QueryWrapper<>();
        q1.orderByAsc("id");
        List<AdminRole> list = this.adminRoleService.list(q1);
        List<Pair<Integer, String>> roleLevelList = list.stream().map(l -> new Pair<>(l.getRoleLevel(), l.getRoleName())).collect(Collectors.toList());
        this.roleVoter = new RoleVoter(roleLevelList);
    }

    /**
     * @param authentication 当前的用户身份信息
     * @param o              当前请求信息
     * @param collection     当前uri需要的角色
     * @throws AccessDeniedException
     * @throws InsufficientAuthenticationException
     */
    @Override
    public void decide(Authentication authentication, Object o, Collection<ConfigAttribute> collection) throws AccessDeniedException, InsufficientAuthenticationException {

        int vote = this.roleVoter.vote(authentication, o, collection);
        if (vote != 1) {
            //非赞同票,参考源码得知需要抛出此注解
            throw new AccessDeniedException("权限不足");
        }

    }

    @Override
    public boolean supports(ConfigAttribute configAttribute) {
        return true;
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return true;
    }

}
